package com.ruihu.admin.module.business.task.manager;

import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruihu.admin.common.constant.JudgeEnum;
import com.ruihu.admin.common.constant.ResponseCodeConst;
import com.ruihu.admin.common.domain.OrderItemDTO;
import com.ruihu.admin.common.domain.ResponseDTO;
import com.ruihu.admin.constant.CommonConst;
import com.ruihu.admin.module.business.task.constant.TaskResponseCodeConst;
import com.ruihu.admin.module.business.task.constant.TaskStatusEnum;
import com.ruihu.admin.module.business.task.dao.SubTaskDao;
import com.ruihu.admin.module.business.task.dao.TaskDao;
import com.ruihu.admin.module.business.task.dao.TaskNodeInstDao;
import com.ruihu.admin.module.business.task.domain.dto.SubTaskQueryDTO;
import com.ruihu.admin.module.business.task.domain.dto.TaskAddDTO;
import com.ruihu.admin.module.business.task.domain.dto.TaskUpdateDTO;
import com.ruihu.admin.module.business.task.domain.entity.SubTaskEntity;
import com.ruihu.admin.module.business.task.domain.entity.TaskEntity;
import com.ruihu.admin.module.business.task.domain.entity.TaskNodeInstEntity;
import com.ruihu.admin.module.business.tasknode.dao.TaskNodeDao;
import com.ruihu.admin.module.business.tasknode.domain.dto.TaskNodeQueryDTO;
import com.ruihu.admin.module.business.tasknode.domain.entity.TaskNodeEntity;
import com.ruihu.admin.module.support.idgenerator.IdGeneratorService;
import com.ruihu.admin.module.support.idgenerator.constant.IdGeneratorEnum;
import com.ruihu.admin.util.BaseEnumUtil;
import com.ruihu.admin.util.RequestTokenUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.jetbrains.annotations.NotNull;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class TaskManager {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    @Autowired
    private TaskDao taskDao;

    @Autowired
    private SubTaskDao subTaskDao;

    @Autowired
    private TaskNodeDao taskNodeDao;

    @Autowired
    private IdGeneratorService idGeneratorService;

    /**
     * 创建子任务列表
     * @param taskEntity
     * @param startNum
     * @param endNum
     * @return
     */
    @NotNull
    private List<SubTaskEntity> createSubTaskEntityList(TaskEntity taskEntity, int startNum, int endNum) {
        List<SubTaskEntity> subTaskEntityList = new ArrayList<>(endNum);
        for (int i = startNum; i <= endNum; i++) {
            SubTaskEntity subTaskEntity = new SubTaskEntity();
            subTaskEntity.setTaskCode(taskEntity.getTaskCode() + StrUtil.DASHED + i);
            subTaskEntity.setMainTaskId(taskEntity.getId());
            subTaskEntity.setStatus(TaskStatusEnum.CREATED.getValue());
            subTaskEntity.setRevision(CommonConst.DEFAULT_OPTI_LOCK_REVISION);
            subTaskEntity.setIsDelete(JudgeEnum.NO.getValue().toString());
            subTaskEntity.setCreateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
            subTaskEntity.setCreateTime(new Date());
            subTaskEntityList.add(subTaskEntity);
        }
        return subTaskEntityList;
    }

    /**
     * 启动任务
     * @param taskEntity
     */
    @Transactional(rollbackFor = Exception.class)
    public void startTask(TaskEntity taskEntity) {
        taskEntity.setStatus(TaskStatusEnum.RUNNING.getValue());
        taskEntity.setUpdateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
        taskEntity.setUpdateTime(new Date());
        int affectCount = this.taskDao.updateByIdIgnoreEmptyValue(taskEntity);
        if (affectCount > 0) {
            // 创建子任务
            List<OrderItemDTO> orderItemDTOList = new ArrayList<>();
            OrderItemDTO orderItemDTO = new OrderItemDTO();
            orderItemDTO.setColumn("task_code");
            orderItemDTO.setAsc(false);
            orderItemDTOList.add(orderItemDTO);
            SubTaskQueryDTO queryDTO = new SubTaskQueryDTO();
            queryDTO.setMainTaskId(taskEntity.getId());
            queryDTO.setOrders(orderItemDTOList);
            List<SubTaskEntity> subTaskEntityList = this.subTaskDao.queryList(queryDTO);
            int startNum = 1;
            // 已经存在的子任务数量小于主任务设置的数量
            if (subTaskEntityList.size() > 0 && subTaskEntityList.size() < taskEntity.getPlanNum()) {
                String subTaskCode = subTaskEntityList.get(0).getTaskCode();
                startNum = Integer.valueOf(subTaskCode.substring(subTaskCode.indexOf(StrUtil.DASHED) + 1)) + 1;
            }
            // 创建子任务和任务环节实例
            SqlSession sqlSession = this.sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
            subTaskEntityList = this.createSubTaskEntityList(taskEntity, startNum, taskEntity.getPlanNum());
            if (subTaskEntityList.size() > 0) {
                String sqlId = SubTaskDao.class.getName() + ".insert";
                for (SubTaskEntity subTaskEntity : subTaskEntityList) {
                    sqlSession.insert(sqlId, subTaskEntity);
                }
                sqlSession.commit();
            }

            // 复制任务环节创建环节实例
            List<TaskNodeEntity> taskNodeEntityList = this.taskNodeDao.queryByList(new TaskNodeQueryDTO());
            if (taskNodeEntityList.size() > 0) {
                String sqlId = TaskNodeInstDao.class.getName() + ".insert";
                taskNodeEntityList.forEach(taskNodeEntity -> {
                    TaskNodeInstEntity taskNodeInstEntity = TaskNodeInstEntity.convertToTaskNodeInstEntity(taskNodeEntity);
                    taskNodeInstEntity.setMainTaskId(taskEntity.getId());
                    taskNodeInstEntity.setRevision(CommonConst.DEFAULT_OPTI_LOCK_REVISION);
                    taskNodeInstEntity.setCreateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
                    taskNodeInstEntity.setCreateTime(new Date());
                    sqlSession.insert(sqlId, taskNodeInstEntity);
                });
                sqlSession.commit();
            }
        }
    }

    /**
     * 更新任务
     * @param updateDTO
     * @param taskEntity
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateTask(TaskUpdateDTO updateDTO, TaskEntity taskEntity) {
        TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(taskEntity.getStatus(), TaskStatusEnum.class);
        if (!TaskStatusEnum.CREATED.equals(taskStatusEnum) && CompareUtil.compare(taskEntity.getPlanNum(), updateDTO.getPlanNum()) < 0) {
            // 创建子任务
            List<OrderItemDTO> orderItemDTOList = new ArrayList<>();
            OrderItemDTO orderItemDTO = new OrderItemDTO();
            orderItemDTO.setColumn("id");
            orderItemDTO.setAsc(false);
            orderItemDTOList.add(orderItemDTO);
            SubTaskQueryDTO queryDTO = new SubTaskQueryDTO();
            queryDTO.setMainTaskId(taskEntity.getId());
            queryDTO.setOrders(orderItemDTOList);
            List<SubTaskEntity> subTaskEntityList = this.subTaskDao.queryList(queryDTO);
            // 已经存在的子任务数量小于主任务设置的数量
            if (subTaskEntityList.size() > 0 && subTaskEntityList.size() < updateDTO.getPlanNum()) {
                String subTaskCode = subTaskEntityList.get(0).getTaskCode();
                int startNum = Integer.valueOf(subTaskCode.substring(subTaskCode.indexOf(StrUtil.DASHED) + 1)) + 1;

                // 创建子任务和任务环节实例
                int taskNum = updateDTO.getPlanNum() - subTaskEntityList.size();
                SqlSession sqlSession = this.sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
                subTaskEntityList = this.createSubTaskEntityList(taskEntity, startNum, startNum + taskNum - 1);
                if (subTaskEntityList.size() > 0) {
                    String sqlId = SubTaskDao.class.getName() + ".insert";
                    for (SubTaskEntity subTaskEntity : subTaskEntityList) {
                        sqlSession.insert(sqlId, subTaskEntity);
                    }
                    sqlSession.commit();

                    // 如果任务为完成，则更新为运行状态
                    if (TaskStatusEnum.COMPLETE.equals(taskStatusEnum))
                        taskEntity.setStatus(TaskStatusEnum.RUNNING.getValue());
                }
            }
        }

        // 更新主任务
        TaskEntity taskEntityTmp = TaskEntity.convertToTaskEntity(updateDTO);
        taskEntity = TaskEntity.copyIgnoreNullAndEmpty(taskEntityTmp, taskEntity);
        taskEntity.setUpdateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
        taskEntity.setUpdateTime(new Date());
        this.taskDao.updateByIdIgnoreEmptyValue(taskEntity);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> add(TaskAddDTO addDTO) {
        if (null == addDTO) {
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);
        }
        QueryWrapper<TaskEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("task_name",addDTO.getTaskName());
        queryWrapper.eq("is_delete", JudgeEnum.NO.getValue());
        Integer count = taskDao.selectCount(queryWrapper);
        if(count > 0){
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NAME_HAS_EXISTS);
        }
        TaskEntity entity = TaskEntity.convertToTaskEntity(addDTO);
        String taskNumber = this.idGeneratorService.generate(IdGeneratorEnum.TASK_NUMBER);
        entity.setTaskCode(taskNumber);
        entity.setStatus(TaskStatusEnum.CREATED.getValue());
        entity.setCreateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
        entity.setCreateTime(new Date());
        entity.setRevision(CommonConst.DEFAULT_OPTI_LOCK_REVISION);
        entity.setIsDelete(JudgeEnum.NO.getValue().toString());
        this.taskDao.insert(entity);

        return ResponseDTO.succ();
    }

    /**
     * 删除任务
     * @param taskEntity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> deleteTask(TaskEntity taskEntity) {
        SubTaskQueryDTO subTaskQueryDTO = new SubTaskQueryDTO();
        subTaskQueryDTO.setMainTaskId(taskEntity.getId());
        List<SubTaskEntity> subTaskEntityList = this.subTaskDao.queryList(subTaskQueryDTO);
        for (SubTaskEntity subTaskEntity : subTaskEntityList) {
            // 删除子任务
            subTaskEntity.setIsDelete(JudgeEnum.YES.getValue().toString());
            this.subTaskDao.deleteById(subTaskEntity.getId());
        }
        // 删除主任务
        taskEntity.setIsDelete(JudgeEnum.YES.getValue().toString());
        this.taskDao.deleteById(taskEntity.getId());

        return ResponseDTO.succ();
    }
}

